package eu.vranckaert.calendar;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.AsyncTask;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import eu.vranckaert.calendar.util.*;
import eu.vranckaert.calendar.util.CalendarView;
import eu.vranckaert.calendar.widget.MonthCellView;
import eu.vranckaert.calendar.widget.MonthView;
import eu.vranckaert.calendar.widget.Workspace;
import eu.vranckaert.calendar.widget.MonthCellView;
import eu.vranckaert.calendar.widget.Workspace;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * User: Dirk Vranckaert
 * Date: 21/02/13
 * Time: 13:57
 */
@SuppressLint("SimpleDateFormat")
public class CalendarMonthView extends CalendarView {
    private MonthCellView.CellViewClickListener cellViewClickListener;
    private WeekDay firstDayOfWeek;

    protected CalendarMonthView(Activity context, Workspace workspace) {
        super(context, workspace, -1);
    }

    public static CalendarMonthView initCalendar(Activity context, Workspace workspace, Date dayInMonth, WeekDay firstDayOfWeek, OnDataLoadListener onDataLoadListener, MonthCellView.CellViewClickListener cellViewClickListener) {
        CalendarMonthView helper = new CalendarMonthView(context, workspace);
        helper.setOnDataLoadListener(onDataLoadListener);
        helper.cellViewClickListener = cellViewClickListener;
        helper.firstDayOfWeek = firstDayOfWeek;
        helper.setupFirstFiveViews(dayInMonth);
        helper.updateNowView(true);

        return helper;
    }

    public class Month extends Data {
        private Date firstDayOfMonth;
        private List<MonthCellView> monthCellViews;

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            Month month = (Month) o;

            if (firstDayOfMonth != null ? !firstDayOfMonth.equals(month.firstDayOfMonth) : month.firstDayOfMonth != null) return false;

            return true;
        }

        @Override
        public int hashCode() {
            return firstDayOfMonth != null ? firstDayOfMonth.hashCode() : 0;
        }
    }

    @Override
    protected void setupFirstFiveViews(Date initDate) {
        initDate = DateUtil.DateTimeConverter.convertDateTimeToDateOnly(initDate);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(initDate);

        calendar.set(Calendar.DAY_OF_MONTH, 1);

        // Two months ago (-2)
        calendar.add(Calendar.MONTH, -2);
        setupView(calendar.getTime(), false);

        // Last month (-1)
        calendar.add(Calendar.MONTH, 1);
        setupView(calendar.getTime(), false);

        // This month (0)
        calendar.add(Calendar.MONTH, 1);
        setupView(calendar.getTime(), false);

        // Next month (1)
        calendar.add(Calendar.MONTH, 1);
        setupView(calendar.getTime(), false);

        // Within two months (2)
        calendar.add(Calendar.MONTH, 1);
        setupView(calendar.getTime(), false);
    }

    private Month setupView(Date date, boolean addToBeginning) {
        Month month = new Month();

        // Setup views
        month.setRootView((ViewGroup) context.getLayoutInflater().inflate(R.layout.cal__month_content, null));

        month.firstDayOfMonth = date;

        if (addToBeginning) {
            workspace.addView(month.getRootView(), 0);
            mData.add(0, month);
        } else {
            workspace.addView(month.getRootView());
            mData.add(month);
        }

        TextView label = (TextView) month.getRootView().findViewById(R.id.calendar_month_label);
        SimpleDateFormat df = new SimpleDateFormat("MMMMM yyyy");
        label.setText(df.format(month.firstDayOfMonth));

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(DateUtil.DateTimeConverter.calculateWeekBoundaries(0, firstDayOfWeek.getWeekday(), context).get(0));

        Date day1 = calendar.getTime();
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        Date day2 = calendar.getTime();
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        Date day3 = calendar.getTime();
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        Date day4 = calendar.getTime();
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        Date day5 = calendar.getTime();
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        Date day6 = calendar.getTime();
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        Date day7 = calendar.getTime();

        View header = month.getRootView().findViewById(R.id.calendar_week_header);

        TextView label1 = (TextView) header.findViewById(R.id.calendar_week_header_1);
        TextView label2 = (TextView) header.findViewById(R.id.calendar_week_header_2);
        TextView label3 = (TextView) header.findViewById(R.id.calendar_week_header_3);
        TextView label4 = (TextView) header.findViewById(R.id.calendar_week_header_4);
        TextView label5 = (TextView) header.findViewById(R.id.calendar_week_header_5);
        TextView label6 = (TextView) header.findViewById(R.id.calendar_week_header_6);
        TextView label7 = (TextView) header.findViewById(R.id.calendar_week_header_7);

        label1.setText(getHeaderDayOfWeek(day1));
        label2.setText(getHeaderDayOfWeek(day2));
        label3.setText(getHeaderDayOfWeek(day3));
        label4.setText(getHeaderDayOfWeek(day4));
        label5.setText(getHeaderDayOfWeek(day5));
        label6.setText(getHeaderDayOfWeek(day6));
        label7.setText(getHeaderDayOfWeek(day7));


        header.setVisibility(View.VISIBLE);
        header.invalidate();
        header.forceLayout();

        MonthView monthView = (MonthView)month.getRootView().findViewById(R.id.calendar_month_cells);
        List<MonthCellView> monthCellViews = monthView.buildCalendarCells(month.firstDayOfMonth, firstDayOfWeek.getWeekday(), cellViewClickListener, context);
        month.monthCellViews = monthCellViews;

        reloadDataForDay(month.firstDayOfMonth);
        return month;
    }

    private String getHeaderDayOfWeek(Date date) {
        DateFormat df = new SimpleDateFormat("E");
        return df.format(date);
    }

    @Override
    protected boolean updateNowView(boolean forceScroll) {
        if (forceScroll) {
            // Scroll to show "now" in center
            workspace.setCurrentScreenFast(CURRENT_INDEX);
            return true;
        }
        return false;
    }

    @Override
    public void onViewChanged(int index) {
        if (index != CURRENT_INDEX) {
            @SuppressWarnings("unused")
			Month newMonth = null;
            if (CURRENT_INDEX < index) {
                // Move forward
                Calendar cal = Calendar.getInstance();
                cal.setTime(((Month)mData.get(CURRENT_INDEX)).firstDayOfMonth);
                cal.add(Calendar.MONTH, 3);

                mData.remove(0);
                workspace.removeViewAt(0);

                newMonth = setupView(cal.getTime(), false);
            } else {
                // Move backwards
                Calendar cal = Calendar.getInstance();
                cal.setTime(((Month)mData.get(CURRENT_INDEX)).firstDayOfMonth);
                cal.add(Calendar.MONTH, -3);

                int indexForRemoval = mData.size() - 1;
                mData.remove(indexForRemoval);
                workspace.removeViewAt(indexForRemoval);

                newMonth = setupView(cal.getTime(), true);
            }

            //reloadDataForDay(newMonth.firstDayOfMonth);

            updateNowView(false);
            super.onViewChanged(index);
        }
    }

    @Override
    public Date getCurrentDate() {
        return ((Month)mData.get(CURRENT_INDEX)).firstDayOfMonth;
    }

    @Override
    public void reloadDataForDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
        Date firstDayOfMonth = calendar.getTime();

        if (getOnDataLoadListener() != null) {
            Month month = new Month();
            month.firstDayOfMonth = firstDayOfMonth;

            if (mData.contains(month)) {
                month = (Month) mData.get(mData.indexOf(month));
                DataLoadingTask dataLoadingTask = new DataLoadingTask();
                AsyncHelper.startWithParams(dataLoadingTask, new Month[]{month});
            }
        }
    }

    private class DataLoadingTask extends AsyncTask<Month, Void, List<Object>> {
        @Override
        protected List<Object> doInBackground(Month... params) {
            Month month = params[0];

            Map<MonthCellView, List<? extends TimeBlock>> timeBlockMap = new HashMap<MonthCellView, List<? extends TimeBlock>>();
            for (MonthCellView monthCellView : month.monthCellViews) {
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(monthCellView.getDate());

                List<? extends TimeBlock> timeBlocks = getOnDataLoadListener().loadDataForDay(calendar.getTime());
                timeBlockMap.put(monthCellView, timeBlocks);
            }

            List<Object> result = new ArrayList<Object>();
            result.add(month);
            result.add(timeBlockMap);

            return result;
        }

        @Override
        protected void onPostExecute(List<Object> result) {
            Month month = (Month) result.get(0);
            @SuppressWarnings("unchecked")
            Map<MonthCellView, List<? extends TimeBlock>> timeBlockMap = ((Map<MonthCellView, List<? extends TimeBlock>>) result.get(1));

            if (mData.contains(month)) {
                for (Map.Entry<MonthCellView, List<? extends TimeBlock>> entry : timeBlockMap.entrySet()) {
                    MonthCellView monthCellView = entry.getKey();
                    monthCellView.removeCount();

                    List<? extends TimeBlock> timeBlocks = entry.getValue();
                    if (timeBlocks != null && !timeBlocks.isEmpty()) {
                        monthCellView.addCount(timeBlocks.size());
                    }
                }
            }
        }
    }

    @Override
    public void reloadAllData() {
        for (Data data : mData) {
            reloadDataForDay(((Month)data).firstDayOfMonth);
        }
    }
}
